package mrpanyu.guitool.yunduan;

import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.codec.binary.Base64;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;

import mrpanyu.guitool.base.annotation.Action;
import mrpanyu.guitool.base.annotation.Parameter;
import mrpanyu.guitool.base.annotation.ToolModel;
import mrpanyu.guitool.base.model.ParameterType;
import mrpanyu.guitool.base.model.Tool;

@ToolModel(displayName = "云端导出-Host端")
public class YunduanExportHost {

	@Parameter(displayName = "输出文件", type = ParameterType.FILE, order = 1)
	private File outputFile;

	@Parameter(displayName = "X轴偏移量", order = 2)
	private int left = 10;

	@Parameter(displayName = "Y轴偏移量", order = 3)
	private int top = 50;

	@Parameter(displayName = "图片大小", order = 4)
	private int imgSize = 1024;

	@Parameter(displayName = "分页大小", description = "仅续传时必须，与跳过分页数一同使用", order = 5)
	private int pageSize = 1024;

	@Parameter(displayName = "跳过分页数", description = "为0时表示传输新文件，大于0表示续传文件", order = 6)
	private int skipPages = 0;

	@Parameter(displayName = "翻页后延迟毫秒", order = 7)
	private int keyDelay = 0;

	private Robot robot;

	private AtomicBoolean stopFlag = new AtomicBoolean(false);

	@Action(displayName = "启动传输", order = 1)
	public void execute(Tool tool) throws Exception {
		tool.clearMessages();
		if (outputFile == null) {
			tool.errorMessage("输出文件不能为空");
			return;
		}
		stopFlag.set(false);
		tool.infoMessage("请将云端导出-VM端二维码窗口至于桌面顶端并保持窗口焦点");
		robot = new Robot();
		boolean append = skipPages > 0;
		int pageNo = skipPages;
		try (FileOutputStream fout = new FileOutputStream(outputFile, append)) {
			while (true) {
				if (stopFlag.get()) {
					tool.warnMessage("已停止");
					break;
				}
				BufferedImage img = robot.createScreenCapture(new Rectangle(left, top, imgSize, imgSize));
				try {
					BufferedImageLuminanceSource luminateSource = new BufferedImageLuminanceSource(img);
					MultiFormatReader reader = new MultiFormatReader();
					Map<DecodeHintType, Object> hints = new HashMap<>();
					hints.put(DecodeHintType.POSSIBLE_FORMATS, EnumSet.allOf(BarcodeFormat.class));
					hints.put(DecodeHintType.TRY_HARDER, true);
					hints.put(DecodeHintType.PURE_BARCODE, true);
					hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
					reader.setHints(hints);
					String text = reader.decode(new BinaryBitmap(new HybridBinarizer(luminateSource))).getText();
					int idx1 = text.indexOf(':');
					int idx2 = text.indexOf(':', idx1 + 1);
					String part1 = text.substring(0, idx1);
					String part2 = text.substring(idx1 + 1, idx2);
					String encoded = text.substring(idx2 + 1);
					int p = Integer.parseInt(part1);
					if (p == pageNo) {
						byte[] data = Base64.decodeBase64(encoded);
						data = AESUtils.decrypt(Constants.AES_KEY, data);
						fout.write(data);
						double kb = (p + 1) * pageSize / 1024.0;
						tool.infoMessage("分页" + (p + 1) + "传输完成，已传输" + kb + "KB");
						if ("*".equals(part2)) {
							tool.infoMessage("文件传输完成");
							closePage();
							break;
						} else {
							pageNo++;
							nextPage();
						}
					} else {
						gotoPage(pageNo);
					}
				} catch (Exception e) {
					tool.infoMessage("未获取到二维码，稍后重试");
					refreshPage();
					// ImageIO.write(img, "PNG", new File("D:\\temp\\a.png"));
					Thread.sleep(500);
				}
			}
		}
	}

	@Action(displayName = "停止传输", order = 2)
	public void stop(Tool tool) {
		stopFlag.set(true);
	}

	private void nextPage() throws Exception {
		robot.keyPress(KeyEvent.VK_CLOSE_BRACKET);
		Thread.sleep(keyDelay);
	}

	private void refreshPage() throws Exception {
		robot.keyPress(KeyEvent.VK_EQUALS);
		Thread.sleep(keyDelay);
	}

	private void closePage() {
		robot.keyPress(KeyEvent.VK_BACK_SLASH);
	}

	private void gotoPage(int p) throws Exception {
		String num = "" + p;
		robot.keyPress(KeyEvent.VK_SEMICOLON);
		Thread.sleep(keyDelay);
		for (char c : num.toCharArray()) {
			robot.keyPress(c);
			Thread.sleep(keyDelay);
		}
		robot.keyPress(KeyEvent.VK_SEMICOLON);
		Thread.sleep(keyDelay);
	}

}
